﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Globalization;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Windows.Threading;
using System.Linq;

namespace Gmantis.Controls
{
    public delegate void CancelEventHandler(object sender, CancelEventArgs e);
    public enum WindowState
    {
        Floating,
        Maximized,
        Minimized
    }

    [TemplatePart(Name = "Resize", Type = typeof(Border)), 
    TemplateVisualState(Name = "Closed", GroupName = "OpenStates"), 
    TemplatePart(Name = "Drag", Type = typeof(FrameworkElement)), 
    TemplatePart(Name = "Root", Type = typeof(FrameworkElement)), 
    TemplatePart(Name = "Close", Type = typeof(Button)), 
    TemplatePart(Name = "Content", Type = typeof(FrameworkElement)), 
    TemplatePart(Name = "Maximize", Type = typeof(Button)), 
    TemplatePart(Name = "Minimize", Type = typeof(Button)), 
    TemplateVisualState(Name = "Active", GroupName = "ActiveStates"), 
    TemplateVisualState(Name = "Inactive", GroupName = "ActiveStates"), 
    TemplateVisualState(Name = "Floating", GroupName = "WindowStateStates"), 
    TemplateVisualState(Name = "Maximized", GroupName = "WindowStateStates"), 
    TemplateVisualState(Name = "Minimized", GroupName = "WindowStateStates"), 
    TemplateVisualState(Name = "Dragged", GroupName = "DragStates"), 
    TemplateVisualState(Name = "Still", GroupName = "DragStates"), 
    TemplateVisualState(Name = "Open", GroupName = "OpenStates")]
    public class GWindow : HeaderedContentControl
    {
        // Fields
        internal Canvas _canvas;
        private Storyboard _closeStoryboard;
        internal Context _context;
        internal static Dictionary<Canvas, Context> _contexts = new Dictionary<Canvas, Context>();
        internal static Canvas _defaultCanvas;
        private DragHelper _dragHelper;
        internal Button _elementClose;
        internal FrameworkElement _elementContent;
        internal FrameworkElement _elementDrag;
        internal Button _elementMaximize;
        internal Button _elementMinimize;
        internal Border _elementResize;
        internal FrameworkElement _elementRoot;
        private bool _hasClosed;
        private bool _hasSetPreviousState;
        private bool _isMinimized;
        private WindowState _previousState;
        private Point _resizeDir;
        private bool _resizing;
        private static bool _rootLoaded;
        private TapHelper _tapHelper;
        private bool _throwIsActiveChanged;
        private bool _throwWindowStateChanged;
        public static readonly DependencyProperty ButtonBackgroundProperty = DependencyProperty.Register("ButtonBackground", typeof(Brush), typeof(GWindow), null);
        public static readonly DependencyProperty ButtonForegroundProperty = DependencyProperty.Register("ButtonForeground", typeof(Brush), typeof(GWindow), null);
        internal const string CloseElementName = "Close";
        internal const string ContentElementName = "Content";
        public static readonly DependencyProperty DialogResultProperty = DependencyProperty.Register("DialogResult", typeof(MessageBoxResult), typeof(GWindow), new PropertyMetadata(MessageBoxResult.None, new PropertyChangedCallback(GWindow.OnDialogResultPropertyChanged)));
        internal const string DragElementName = "Drag";
        private bool internalLoaded;
        public static readonly DependencyProperty IsActiveProperty = DependencyProperty.Register("IsActive", typeof(bool), typeof(GWindow), new PropertyMetadata(new PropertyChangedCallback(GWindow.OnIsActivePropertyChanged)));
        public static readonly DependencyProperty IsDraggableProperty = DependencyProperty.Register("IsDraggable", typeof(bool), typeof(GWindow), new PropertyMetadata(true));
        internal static readonly DependencyProperty IsDraggingProperty = DependencyProperty.Register("IsDragging", typeof(bool), typeof(GWindow), new PropertyMetadata(new PropertyChangedCallback(GWindow.OnIsDraggingPropertyChanged)));
        public static readonly DependencyProperty IsResizableProperty = DependencyProperty.Register("IsResizable", typeof(bool), typeof(GWindow), new PropertyMetadata(true, new PropertyChangedCallback(GWindow.OnIsResizablePropertyChanged)));
        public static readonly DependencyProperty LeftProperty = DependencyProperty.Register("Left", typeof(double), typeof(GWindow), new PropertyMetadata(new PropertyChangedCallback(GWindow.OnLeftPropertyChanged)));
        internal const string MaximizeElementName = "Maximize";
        private const int maxWindowHistory = 5;
        internal const string MinimizeElementName = "Minimize";
        private Size minSize;
        public static readonly DependencyProperty ModalBackgroundProperty = DependencyProperty.Register("ModalBackground", typeof(Brush), typeof(GWindow), null);
        public static readonly DependencyProperty MouseOverBrushProperty = DependencyProperty.Register("MouseOverBrush", typeof(Brush), typeof(GWindow), null);
        public static readonly DependencyProperty PressedBrushProperty = DependencyProperty.Register("PressedBrush", typeof(Brush), typeof(GWindow), null);
        internal const string ResizeElementName = "Resize";
        private Rect restore;
        internal const string RootElementName = "Root";
        public static readonly DependencyProperty ShowCloseButtonProperty = DependencyProperty.Register("ShowCloseButton", typeof(bool), typeof(GWindow), new PropertyMetadata(true, new PropertyChangedCallback(GWindow.OnShowCloseButtonPropertyChanged)));
        public static readonly DependencyProperty ShowMaximizeButtonProperty = DependencyProperty.Register("ShowMaximizeButton", typeof(bool), typeof(GWindow), new PropertyMetadata(true, new PropertyChangedCallback(GWindow.OnShowMaximizeButtonPropertyChanged)));
        public static readonly DependencyProperty ShowMinimizeButtonProperty = DependencyProperty.Register("ShowMinimizeButton", typeof(bool), typeof(GWindow), new PropertyMetadata(true, new PropertyChangedCallback(GWindow.OnShowMinimizeButtonPropertyChanged)));
        private DispatcherTimer timer;
        public static readonly DependencyProperty TopProperty = DependencyProperty.Register("Top", typeof(double), typeof(GWindow), new PropertyMetadata(new PropertyChangedCallback(GWindow.OnTopPropertyChanged)));
        private double virtualHeight;
        private double virtualWidth;
        public static readonly DependencyProperty WindowStateProperty = DependencyProperty.Register("WindowState", typeof(WindowState), typeof(GWindow), new PropertyMetadata(WindowState.Floating, new PropertyChangedCallback(GWindow.OnWindowStatePropertyChanged)));
        private EventHandler winUnloadTimerTickHandler;
        private const int ZIndex = -10000;

        // Events
        public event EventHandler Closed;
        public event CancelEventHandler Closing;
        public event EventHandler<PropertyChangedEventArgs<bool>> IsActiveChanged;
        public event EventHandler<PositionChangedEventArgs> PositionChanged;
        public event EventHandler<PropertyChangedEventArgs<WindowState>> WindowStateChanged;

        // Methods
        public GWindow()
        {
            RoutedEventHandler handler = null;
            this._throwIsActiveChanged = true;
            this._throwWindowStateChanged = true;
            base.DefaultStyleKey = typeof(GWindow);
            if (handler == null)
            {
                handler = delegate(object param0, RoutedEventArgs param1)
                {
                    this.ChangeVisualStateActive(false);
                    this.ChangeVisualStateWindowState(false);
                    this.ChangeVisualStateDrag(false);
                };
            }
            base.Loaded += handler;
            this.SetCustomDefaultValues();
        }

        public static void AddDefaultPopupToVisualTree(Panel panel)
        {
            InitializeDefaultCanvas();
            panel.Children.Add(_defaultCanvas.Parent as UIElement);
        }

        private static void AttachApplicationRoot()
        {
            FrameworkElement root;
            if (!_rootLoaded)
            {
                root = Application.Current.RootVisual as FrameworkElement;
                if (root != null)
                {
                    Action wakeUpCanvas = delegate
                    {
                        Grid grid = new Grid();
                        _defaultCanvas.Children.Add(grid);
                        _defaultCanvas.Children.Remove(grid);
                    };
                    root.SizeChanged += delegate(object s, SizeChangedEventArgs e)
                    {
                        _defaultCanvas.Width = root.ActualWidth;
                        _defaultCanvas.Height = root.ActualHeight;
                        wakeUpCanvas();
                    };
                    _defaultCanvas.Width = root.ActualWidth;
                    _defaultCanvas.Height = root.ActualHeight;
                    _rootLoaded = true;
                    EventHandler layoutUpdated = null;
                    layoutUpdated = delegate(object s, EventArgs e)
                    {
                        wakeUpCanvas();
                        _defaultCanvas.LayoutUpdated -= layoutUpdated;
                    };
                    _defaultCanvas.LayoutUpdated += layoutUpdated;
                    _defaultCanvas.Loaded += (s, e) => wakeUpCanvas();
                }
            }
        }

        private double BoundHeight(double height)
        {
            this.minSize.Height = Math.Max(this.minSize.Height, base.ActualHeight - this._elementContent.ActualHeight);
            double num = Math.Max(base.MinHeight, Math.Max(this._elementRoot.MinHeight, this.minSize.Height));
            double num2 = Math.Min(base.MaxHeight, this._elementRoot.MaxHeight);
            return Math.Min(Math.Max(height, num), num2);
        }

        private double BoundWidth(double width)
        {
            this.minSize.Width = Math.Max(this.minSize.Width, base.ActualWidth - this._elementContent.ActualWidth);
            double num = Math.Max(base.MinWidth, Math.Max(this._elementRoot.MinWidth, this.minSize.Width));
            double num2 = Math.Min(base.MaxWidth, this._elementRoot.MaxWidth);
            return Math.Min(Math.Max(width, num), num2);
        }

        private void BringPopupToFront()
        {
            _contexts[_defaultCanvas].Popup.IsOpen = false;
            _contexts[_defaultCanvas].Popup.IsOpen = true;
            base.Dispatcher.BeginInvoke(delegate
            {
                Control control = this.GetLogicalFocusedElement() as Control;
                if (control != null)
                {
                    control.Focus();
                }
            });
        }

        public void BringToFront()
        {
            if (!this._hasClosed && !this.internalLoaded)
            {
                this._context.WindowOrder.Remove(this);
                this._context.WindowOrder.Add(this);
                this.fixWindowOrder();
                this.IsActive = true;
            }
        }

        internal void CanvasSizeChanged(object sender, SizeChangedEventArgs e)
        {
            if (this.WindowState == WindowState.Maximized)
            {
                base.Width = this.Canvas.ActualWidth;
                base.Height = this.Canvas.ActualHeight;
            }
            else
            {
                if ((this.Left + base.ActualWidth) > this.Canvas.ActualWidth)
                {
                    this.Left = this.Canvas.ActualWidth - base.ActualWidth;
                }
                if ((this.Top + base.ActualHeight) > this.Canvas.ActualHeight)
                {
                    this.Top = this.Canvas.ActualHeight - base.ActualHeight;
                }
                if (this.Left < 0.0)
                {
                    this.Left = 0.0;
                }
                if (this.Top < 0.0)
                {
                    this.Top = 0.0;
                }
            }
            this._context.ModalLayer.Width = this.Canvas.ActualWidth;
            this._context.ModalLayer.Height = this.Canvas.ActualHeight;
            RectangleGeometry geometry = new RectangleGeometry
            {
                Rect = new Rect(0.0, 0.0, this._canvas.ActualWidth, this._canvas.ActualHeight)
            };
            this._canvas.Clip = geometry;
            this.fixWindowOrder();
        }

        public void CenterOnScreen()
        {
            this.OnLayout(delegate
            {
                if (this.CanvasWidth < base.ActualWidth)
                {
                    this.Left = 0.0;
                }
                else
                {
                    this.Left = (this.CanvasWidth - base.ActualWidth) / 2.0;
                }
                if (this.CanvasHeight < base.ActualHeight)
                {
                    this.Top = 0.0;
                }
                else
                {
                    this.Top = (this.CanvasHeight - base.ActualHeight) / 2.0;
                }
            });
        }

        protected void ChangeVisualStateActive(bool useTransitions)
        {
            if (!this.IsActive)
            {
                VisualStateHelper.GoToState(this, "Inactive", useTransitions);
            }
            if (this.IsActive)
            {
                VisualStateHelper.GoToState(this, "Active", useTransitions);
            }
        }

        protected void ChangeVisualStateDrag(bool useTransitions)
        {
            if (!this.IsDragging)
            {
                VisualStateHelper.GoToState(this, "Still", useTransitions);
            }
            if (this.IsDragging)
            {
                VisualStateHelper.GoToState(this, "Dragged", useTransitions);
            }
        }

        protected void ChangeVisualStateWindowState(bool useTransitions)
        {
            if (this.WindowState == WindowState.Minimized)
            {
                VisualStateHelper.GoToState(this, "Minimized", useTransitions);
            }
            if (this.WindowState == WindowState.Maximized)
            {
                VisualStateHelper.GoToState(this, "Maximized", useTransitions);
            }
            if (this.WindowState == WindowState.Floating)
            {
                VisualStateHelper.GoToState(this, "Floating", useTransitions);
            }
        }

        public void Close()
        {
            if (!this._hasClosed)
            {
                if (this.Closing != null)
                {
                    CancelEventArgs e = new CancelEventArgs();
                    this.Closing(this, e);
                    if (e.Cancel)
                    {
                        this.DialogResult = MessageBoxResult.None;
                        return;
                    }
                }
                VisualStateManager.GoToState(this, "Closed", true);
                if (this._closeStoryboard == null)
                {
                    this.OnCloseCompleted();
                }
            }
        }

        private void fixWindowOrder()
        {
            if (this._elementRoot != null)
            {
                base.Dispatcher.BeginInvoke(delegate
                {
                    int num = 0;
                    foreach (GWindow window in this._context.WindowOrder)
                    {
                        window.SetValue(Canvas.ZIndexProperty, num++);
                    }
                    this._canvas.Children.Remove(this._context.ModalLayer);
                    List<GWindow> list = (from w in this._context.ModalWindow
                                           where w.Visibility == Visibility.Visible
                                           select w).ToList<GWindow>();
                    if (list.Count > 0)
                    {
                        foreach (GWindow window2 in list)
                        {
                            window2.SetValue(Canvas.ZIndexProperty, num++);
                        }
                        GWindow window3 = list[list.Count - 1];
                        window3.SetValue(Canvas.ZIndexProperty, num + 1);
                        this._context.ModalLayer.Fill = window3.ModalBackground;
                        this._context.ModalLayer.SetValue(Canvas.ZIndexProperty, num);
                        this._canvas.Children.Add(this._context.ModalLayer);
                    }
                });
            }
        }

        private Point GetResizeDirection(Point pos)
        {
            Point point = new Point();
            if (pos.X < this._elementResize.BorderThickness.Left)
            {
                point.X = -1.0;
            }
            else if (pos.X >= (this._elementResize.ActualWidth - this._elementResize.BorderThickness.Right))
            {
                point.X = 1.0;
            }
            if (pos.Y < this._elementResize.BorderThickness.Top)
            {
                point.Y = -1.0;
                return point;
            }
            if (pos.Y >= (this._elementResize.ActualHeight - this._elementResize.BorderThickness.Bottom))
            {
                point.Y = 1.0;
            }
            return point;
        }

        private T GetTemplateChild<T>(string childName, bool required, ref string errors) where T : class
        {
            DependencyObject templateChild = base.GetTemplateChild(childName);
            ApplyTemplateHelper.VerifyTemplateChild(typeof(T), "template part", childName, templateChild, required, ref errors);
            return (templateChild as T);
        }

        private static Storyboard GetTemplateChildResource(FrameworkElement root, string resourceName, bool required, ref string errors)
        {
            return GetTemplateChildResource<Storyboard>(root, resourceName, required, ref errors);
        }

        private static T GetTemplateChildResource<T>(FrameworkElement root, string resourceName, bool required, ref string errors) where T : class
        {
            object child = root.Resources[resourceName];
            ApplyTemplateHelper.VerifyTemplateChild(typeof(T), "resource", resourceName, child, required, ref errors);
            return (child as T);
        }

        public void Hide()
        {
            base.Visibility = Visibility.Collapsed;
            base.IsEnabled = false;
            this.fixWindowOrder();
        }

        internal void HideHeader()
        {
            if (this._elementDrag != null)
            {
                this._elementDrag.Visibility = Visibility.Collapsed;
            }
        }

        private void InitializeClosePart()
        {
            this._elementClose.Click += (s, e) => this.DialogResult = MessageBoxResult.Cancel;
        }

        private static void InitializeDefaultCanvas()
        {
            if (_defaultCanvas == null)
            {
                _defaultCanvas = new Canvas();
                Context context = new Context();
                _contexts[_defaultCanvas] = context;
                _defaultCanvas.SetValue(Canvas.ZIndexProperty, -10000);
                context.Popup = new Popup();
                if (!DesignerProperties.GetIsInDesignMode(context.Popup))
                {
                    context.Popup.Child = _defaultCanvas;
                }
                context.Popup.IsOpen = true;
                AttachApplicationRoot();
            }
        }

        private void InitializeDragPart()
        {
            this._tapHelper = new TapHelper(this._elementDrag, false);
            this._dragHelper = new DragHelper(this._elementDrag, DragHelperMode.TranslateXY, 1.0, true, false, false, false);
            this._tapHelper.DoubleTapped += delegate(object s, TappedEventArgs e)
            {
                if (this.IsResizable)
                {
                    this.ToggleMaximized();
                }
            };
            Point previousPoint = new Point();
            this._dragHelper.DragStarted += delegate(object s, DragStartedEventArgs e)
            {
                this.IsDragging = true;
                previousPoint = e.GetPosition(this._canvas);
            };
            this._dragHelper.DragCompleted += (s, e) => this.IsDragging = false;
            this._dragHelper.DragDelta += delegate(object s, DragDeltaEventArgs e)
            {
                if (((this.WindowState != WindowState.Maximized) && this.IsDraggable) && !this._hasClosed)
                {
                    Size size = new Size(this.CanvasWidth, this.CanvasHeight);
                    Point position = e.GetPosition(this._canvas);
                    double introduced2 = Math.Min(size.Width, Math.Max(position.X, 0.0));
                    this.Left += introduced2 - Math.Min(size.Width, Math.Max(previousPoint.X, 0.0));
                    double introduced3 = Math.Min(size.Height, Math.Max(position.Y, 0.0));
                    this.Top += introduced3 - Math.Min(size.Height, Math.Max(previousPoint.Y, 0.0));
                    previousPoint = position;
                    this.InvalidateMeasure();
                }
            };
        }

        private void InitializeMaximizePart()
        {
            this._elementMaximize.Click += (s, e) => this.ToggleMaximized();
        }

        private void InitializeMinimizePart()
        {
            this._elementMinimize.Click += (s, e) => this.ToggleMinimized();
        }

        private void InitializeResizePart()
        {
            DragHelper helper = new DragHelper(this._elementResize, DragHelperMode.TranslateXY, 1.0, true, false, false, false);
            helper.DragStarted += new EventHandler<DragStartedEventArgs>(this.OnResizeStarted);
            helper.DragDelta += new EventHandler<DragDeltaEventArgs>(this.OnResizeDelta);
            helper.DragCompleted += new EventHandler<DragCompletedEventArgs>(this.OnResizeCompleted);
            this._elementResize.MouseMove += delegate(object s, MouseEventArgs e)
            {
                if (!this._hasClosed)
                {
                    this.ResizeMouseMove(e);
                }
            };
        }

        private void OnAfterApplyTemplate()
        {
            EventHandler handler = null;
            IEnumerable<VisualStateGroup> source = VisualStateManager.GetVisualStateGroups(this._elementRoot).Cast<VisualStateGroup>();
            if (source != null)
            {
                VisualStateGroup group = source.FirstOrDefault<VisualStateGroup>(vsg => vsg.Name == "OpenStates");
                if (group != null)
                {
                    VisualState state = group.States.Cast<VisualState>().FirstOrDefault<VisualState>(s => s.Name == "Closed");
                    if ((state != null) && (state.Storyboard != null))
                    {
                        this._closeStoryboard = state.Storyboard;
                        if (handler == null)
                        {
                            handler = (s, e) => this.OnCloseCompleted();
                        }
                        this._closeStoryboard.Completed += handler;
                    }
                }
            }
            this.restore = new Rect(this.Left, this.Top, base.Width, base.Height);
            this.OnWindowStateChanged(WindowState.Floating);
            this.OnIsResizableChanged(false);
            this.OnShowMaximizeButtonChanged(false);
            this.OnShowMinimizeButtonChanged(false);
            this.OnShowCloseButtonChanged(false);
            AttachApplicationRoot();
        }

        public override void OnApplyTemplate()
        {
            string errors = string.Empty;
            base.OnApplyTemplate();
            this._elementDrag = this.GetTemplateChild<FrameworkElement>("Drag", false, ref errors);
            if (this._elementDrag != null)
            {
                this.InitializeDragPart();
            }
            this._elementRoot = this.GetTemplateChild<FrameworkElement>("Root", true, ref errors);
            this._elementClose = this.GetTemplateChild<Button>("Close", false, ref errors);
            if (this._elementClose != null)
            {
                this.InitializeClosePart();
            }
            this._elementResize = this.GetTemplateChild<Border>("Resize", false, ref errors);
            if (this._elementResize != null)
            {
                this.InitializeResizePart();
            }
            this._elementContent = this.GetTemplateChild<FrameworkElement>("Content", true, ref errors);
            this._elementMaximize = this.GetTemplateChild<Button>("Maximize", false, ref errors);
            if (this._elementMaximize != null)
            {
                this.InitializeMaximizePart();
            }
            this._elementMinimize = this.GetTemplateChild<Button>("Minimize", false, ref errors);
            if (this._elementMinimize != null)
            {
                this.InitializeMinimizePart();
            }
            if (!string.IsNullOrEmpty(errors))
            {
                if ((base.Template != null) && !PlatformIndependent.IsInDesignMode(this))
                {
                    throw new InvalidOperationException(string.Format(CultureInfo.InvariantCulture, "Template cannot be applied to GWindow.\nDetails: {0}", new object[] { errors }));
                }
            }
            else
            {
                this.ChangeVisualStateActive(false);
                this.ChangeVisualStateWindowState(false);
                this.ChangeVisualStateDrag(false);
                this.OnAfterApplyTemplate();
            }
        }

        private void OnCloseCompleted()
        {
            this._context.ModalWindow.Remove(this);
            if (this._context.ActiveWindow == this)
            {
                this._context.ActiveWindow = null;
            }
            while (this._context.PreviousActiveWindows.Remove(this))
            {
            }
            if (this._context.PreviousActiveWindows.Count > 0)
            {
                this._context.PreviousActiveWindows.Last<GWindow>().IsActive = true;
            }
            this._context.WindowOrder.Remove(this);
            this.fixWindowOrder();
            base.Visibility = Visibility.Collapsed;
            this._canvas.SizeChanged -= new SizeChangedEventHandler(this.CanvasSizeChanged);
            this._canvas.Children.Remove(this);
            this._hasClosed = true;
            if (this._context.ActiveWindow != null)
            {
                this._context.ActiveWindow.Focus();
            }
            if (this.Closed != null)
            {
                this.Closed(this, EventArgs.Empty);
            }
        }

        private void OnDialogResultChanged(MessageBoxResult oldValue)
        {
            if (!DesignerProperties.GetIsInDesignMode(this) && (this.DialogResult != MessageBoxResult.None))
            {
                this.Close();
            }
        }

        private static void OnDialogResultPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            GWindow window = d as GWindow;
            MessageBoxResult oldValue = (MessageBoxResult)e.OldValue;
            window.OnDialogResultChanged(oldValue);
        }

        protected override void OnGotFocus(RoutedEventArgs e)
        {
            FrameworkElement descendant = this.GetLogicalFocusedElement();
            if (this.IsVisualOrLogicalParentOf(descendant))
            {
                this.BringToFront();
            }
        }

        private void OnIsActiveChanged(bool oldValue)
        {
            if (!this._hasClosed)
            {
                if ((!this.IsActive && (this._context.ActiveWindow == this)) || (((this._context.ActiveWindow != this) && (this._context.ActiveWindow != null)) && (this._context.PreviousActiveWindows.LastOrDefault<GWindow>() != this._context.ActiveWindow)))
                {
                    this._context.PreviousActiveWindows.Add(this._context.ActiveWindow);
                    while (this._context.PreviousActiveWindows.Count > 5)
                    {
                        this._context.PreviousActiveWindows.RemoveAt(0);
                    }
                }
                if (this.IsActive)
                {
                    if ((this._context.ActiveWindow != this) && (this._context.ActiveWindow != null))
                    {
                        this._context.ActiveWindow.IsActive = false;
                    }
                    this._context.ActiveWindow = this;
                }
                else if (this._context.ActiveWindow == this)
                {
                    this._context.ActiveWindow = null;
                }
            }
        }

        private static void OnIsActivePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            GWindow sender = d as GWindow;
            bool oldValue = (bool)e.OldValue;
            sender.OnIsActiveChanged(oldValue);
            if ((sender.IsActiveChanged != null) && sender._throwIsActiveChanged)
            {
                PropertyChangedEventArgs<bool> args = new PropertyChangedEventArgs<bool>
                {
                    OldValue = (bool)e.OldValue,
                    NewValue = (bool)e.NewValue
                };
                sender.IsActiveChanged(sender, args);
            }
            sender.ChangeVisualStateActive(true);
        }

        private static void OnIsDraggingPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            (d as GWindow).ChangeVisualStateDrag(true);
        }

        private void OnIsResizableChanged(bool oldValue)
        {
            if (this._elementResize != null)
            {
                this.UpdateResize();
            }
            this.OnShowMaximizeButtonChanged(this.ShowMaximizeButton);
        }

        private static void OnIsResizablePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            GWindow window = d as GWindow;
            bool oldValue = (bool)e.OldValue;
            window.OnIsResizableChanged(oldValue);
        }

        private void OnLayout(Action a)
        {
            EventHandler handler = delegate(object s, EventArgs e)
            {
            };
            handler = delegate(object s, EventArgs e)
            {
                a();
                this.LayoutUpdated -= handler;
            };
            base.LayoutUpdated += handler;
            base.InvalidateMeasure();
        }

        private void OnLeftChanged(double oldValue)
        {
            base.SetValue(Canvas.LeftProperty, Math.Round(this.Left));
        }

        private static void OnLeftPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            GWindow window = d as GWindow;
            double oldValue = (double)e.OldValue;
            window.OnLeftChanged(oldValue);
        }

        private void OnResizeCompleted(object sender, DragCompletedEventArgs e)
        {
            this._resizeDir = new Point();
            this._resizing = false;
        }

        private void OnResizeDelta(object sender, DragDeltaEventArgs e)
        {
            this.Resize(e.DeltaTranslation);
        }

        private void OnResizeStarted(object sender, DragStartedEventArgs e)
        {
            this._resizing = true;
            base.Width = this.virtualWidth = base.ActualWidth;
            base.Height = this.virtualHeight = base.ActualHeight;
        }

        private void OnShowCloseButtonChanged(bool oldValue)
        {
            if (this._elementClose != null)
            {
                this._elementClose.Visibility = this.ShowCloseButton ? Visibility.Visible : Visibility.Collapsed;
            }
        }

        private static void OnShowCloseButtonPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            GWindow window = d as GWindow;
            bool oldValue = (bool)e.OldValue;
            window.OnShowCloseButtonChanged(oldValue);
        }

        private void OnShowMaximizeButtonChanged(bool oldValue)
        {
            if (this._elementMaximize != null)
            {
                this._elementMaximize.Visibility = (this.IsResizable && this.ShowMaximizeButton) ? Visibility.Visible : Visibility.Collapsed;
            }
        }

        private static void OnShowMaximizeButtonPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            GWindow window = d as GWindow;
            bool oldValue = (bool)e.OldValue;
            window.OnShowMaximizeButtonChanged(oldValue);
        }

        private void OnShowMinimizeButtonChanged(bool oldValue)
        {
            if (this._elementMinimize != null)
            {
                this._elementMinimize.Visibility = this.ShowMinimizeButton ? Visibility.Visible : Visibility.Collapsed;
            }
        }

        private static void OnShowMinimizeButtonPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            GWindow window = d as GWindow;
            bool oldValue = (bool)e.OldValue;
            window.OnShowMinimizeButtonChanged(oldValue);
        }

        private void OnTopChanged(double oldValue)
        {
            base.SetValue(Canvas.TopProperty, Math.Round(this.Top));
        }

        private static void OnTopPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            GWindow window = d as GWindow;
            double oldValue = (double)e.OldValue;
            window.OnTopChanged(oldValue);
        }

        private void OnWindowStateChanged(WindowState oldValue)
        {
            this._previousState = oldValue;
            if (this.WindowState == WindowState.Maximized)
            {
                this.restore = new Rect(this.Left, this.Top, base.Width, base.Height);
                this.Left = 0.0;
                this.Top = 0.0;
                if (Application.Current.RootVisual != null)
                {
                    base.Width = this.CanvasWidth;
                    base.Height = this.CanvasHeight;
                }
            }
            else if (oldValue == WindowState.Maximized)
            {
                this.Left = this.restore.Left;
                this.Top = this.restore.Top;
                base.Width = this.restore.Width;
                base.Height = this.restore.Height;
            }
            this.UpdateResize();
            this._hasSetPreviousState = true;
        }

        private static void OnWindowStatePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            GWindow sender = d as GWindow;
            WindowState oldValue = (WindowState)e.OldValue;
            sender.OnWindowStateChanged(oldValue);
            if ((sender.WindowStateChanged != null) && sender._throwWindowStateChanged)
            {
                PropertyChangedEventArgs<WindowState> args = new PropertyChangedEventArgs<WindowState>
                {
                    OldValue = (WindowState)e.OldValue,
                    NewValue = (WindowState)e.NewValue
                };
                sender.WindowStateChanged(sender, args);
            }
            sender.ChangeVisualStateWindowState(true);
        }

        public void Position(Anchor windowAnchor, FrameworkElement reference, Anchor referenceAnchor)
        {
            this.OnLayout(delegate
            {
                Point point = PopupUtil.TestPosition(this, windowAnchor, reference, referenceAnchor, 0.0, 0.0);
                try
                {
                    point = Application.Current.RootVisual.TransformToVisual(this._canvas).Transform(point);
                }
                catch
                {
                }
                this.Left = point.X;
                this.Top = point.Y;
            });
        }

        internal void Resize(Point delta)
        {
            double num = this._resizeDir.X * delta.X;
            double num2 = this._resizeDir.Y * delta.Y;
            this.virtualWidth += num;
            this.virtualHeight += num2;
            double num3 = this.BoundWidth(this.virtualWidth);
            double num4 = this.BoundHeight(this.virtualHeight);
            double num5 = num3 - base.Width;
            double num6 = num4 - base.Height;
            if (this._resizeDir.X < 0.0)
            {
                this.Left -= num5;
            }
            if (this._resizeDir.Y < 0.0)
            {
                this.Top -= num6;
            }
            base.Width = num3;
            base.Height = num4;
        }

        private void ResizeMouseMove(MouseEventArgs e)
        {
            if (!this._resizing)
            {
                this._resizeDir = this.GetResizeDirection(e.GetPosition(this._elementResize));
                if (base.FlowDirection == FlowDirection.RightToLeft)
                {
                    this._resizeDir.X = -this._resizeDir.X;
                }
                if (((this._resizeDir.X == -1.0) && (this._resizeDir.Y == -1.0)) || ((this._resizeDir.X == 1.0) && (this._resizeDir.Y == 1.0)))
                {
                    this._elementResize.Cursor = Cursors.SizeNWSE;
                }
                else if (((this._resizeDir.X == -1.0) && (this._resizeDir.Y == 1.0)) || ((this._resizeDir.X == 1.0) && (this._resizeDir.Y == -1.0)))
                {
                    this._elementResize.Cursor = Cursors.SizeNESW;
                }
                else if (this._resizeDir.X != 0.0)
                {
                    this._elementResize.Cursor = Cursors.SizeWE;
                }
                else if (this._resizeDir.Y != 0.0)
                {
                    this._elementResize.Cursor = Cursors.SizeNS;
                }
                else
                {
                    this._elementResize.Cursor = Cursors.Arrow;
                }
            }
        }

        private void SetCustomDefaultValues()
        {
            InitializeDefaultCanvas();
            base.IsEnabled = true;
            MouseButtonEventHandler handler = delegate(object s, MouseButtonEventArgs e)
            {
                e.Handled = true;
                this.BringToFront();
                FrameworkElement reference = this.GetLogicalFocusedElement();
                if ((reference != null) && (reference != this))
                {
                    while (reference != null)
                    {
                        if ((reference == this) || (((reference is Popup) && (VisualTreeHelper.GetParent(reference) == null)) && (reference.Parent == null)))
                        {
                            return;
                        }
                        reference = (VisualTreeHelper.GetParent(reference) ?? reference.Parent) as FrameworkElement;
                    }
                    base.Focus();
                }
            };
            base.AddHandler(UIElement.MouseLeftButtonDownEvent, handler, true);
            base.LostFocus += delegate(object s, RoutedEventArgs e)
            {
                FrameworkElement descendant = this.GetLogicalFocusedElement();
                if (!this.IsVisualOrLogicalParentOf(descendant))
                {
                    if (this._isMinimized)
                    {
                        this._isMinimized = false;
                    }
                    else
                    {
                        this.IsActive = false;
                    }
                }
            };
            this.Canvas = _defaultCanvas;
            double left = 0.0;
            double top = 0.0;
            base.LayoutUpdated += delegate(object param0, EventArgs param1)
            {
                if ((this.Left != left) || (this.Top != top))
                {
                    if (this.PositionChanged != null)
                    {
                        this.PositionChanged(this, new PositionChangedEventArgs(new Point(left, top)));
                    }
                    left = this.Left;
                    top = this.Top;
                }
            };
            base.Loaded += delegate(object param0, RoutedEventArgs param1)
            {
                VisualStateManager.GoToState(this, "Open", true);
                if (this.timer != null)
                {
                    this.internalLoaded = true;
                }
            };
            base.Unloaded += delegate(object param0, RoutedEventArgs param1)
            {
                if (this.timer != null)
                {
                    this.timer.Stop();
                    this.timer.Tick -= this.winUnloadTimerTickHandler;
                    this.timer = null;
                }
                this.timer = new DispatcherTimer();
                this.timer.Interval = new TimeSpan(0, 0, 0, 0, 100);
                this.winUnloadTimerTickHandler = new EventHandler(this.timer_Tick);
                this.timer.Tick += this.winUnloadTimerTickHandler;
                this.timer.Start();
            };
            VisualStateManager.GoToState(this, "Closed", false);
        }

        public void Show()
        {
            this.VerifyCanShow();
            if (!this._canvas.Children.Contains(this))
            {
                this._canvas.Children.Add(this);
            }
            VerifyDefaultCanvasInserted();
            base.Visibility = Visibility.Visible;
            base.IsEnabled = true;
            this.BringToFront();
            this.BringPopupToFront();
        }

        public void ShowModal()
        {
            RoutedEventHandler handler = null;
            this.VerifyCanShow();
            if (this._canvas.Children.Contains(this) && (base.Visibility == Visibility.Visible))
            {
                throw new InvalidOperationException("ShowModal can be called only on hidden windows.");
            }
            if (!this._canvas.Children.Contains(this))
            {
                this._canvas.Children.Add(this);
            }
            VerifyDefaultCanvasInserted();
            this._context.ModalWindow.Remove(this);
            this._context.ModalWindow.Add(this);
            base.TabNavigation = KeyboardNavigationMode.Cycle;
            base.SetValue(Canvas.ZIndexProperty, 0x186a0);
            this.IsActive = true;
            base.Visibility = Visibility.Visible;
            base.IsEnabled = true;
            if (!base.Focus())
            {
                base.IsTabStop = true;
                base.IsTabStop = false;
                if (handler == null)
                {
                    handler = (s, e) => base.Focus();
                }
                base.Loaded += handler;
            }
            this.BringPopupToFront();
        }

        private void timer_Tick(object sender, EventArgs e)
        {
            this.internalLoaded = false;
            if (this.timer != null)
            {
                this.timer.Stop();
                this.timer.Tick -= this.winUnloadTimerTickHandler;
                this.timer = null;
            }
        }

        private void ToggleMaximized()
        {
            this.WindowState = (this.WindowState == WindowState.Maximized) ? WindowState.Floating : WindowState.Maximized;
        }

        private void ToggleMinimized()
        {
            this.WindowState = (this.WindowState == WindowState.Minimized) ? this._previousState : WindowState.Minimized;
            this._isMinimized = true;
        }

        private void UpdateResize()
        {
            if (this._elementResize != null)
            {
                this._elementResize.IsHitTestVisible = this.IsResizable && (this.WindowState == WindowState.Floating);
            }
        }

        private void VerifyCanShow()
        {
            if (this._hasClosed)
            {
                throw new InvalidOperationException("Cannot call Show or ShowModal after window has closed.");
            }
        }

        private static void VerifyDefaultCanvasInserted()
        {
        }

        // Properties
        public Brush ButtonBackground
        {
            get { return (Brush)GetValue(ButtonBackgroundProperty); }
            set { SetValue(ButtonBackgroundProperty, value); }
        }

        public Brush ButtonForeground
        {
            get { return (Brush)GetValue(ButtonForegroundProperty); }
            set { SetValue(ButtonForegroundProperty, value); }
        }

        public Canvas Canvas
        {
            get
            {
                return this._canvas;
            }
            set
            {
                if (value == null)
                {
                    throw new ArgumentNullException("value");
                }
                if (this._hasClosed || ((this._canvas != null) && this._canvas.Children.Contains(this)))
                {
                    throw new InvalidOperationException("Cannot change Canvas when window has opened");
                }
                if (this._canvas != null)
                {
                    this._canvas.SizeChanged -= new SizeChangedEventHandler(this.CanvasSizeChanged);
                    this._context.WindowOrder.Remove(this);
                    this.fixWindowOrder();
                }
                this._canvas = value;
                this._canvas.SizeChanged += new SizeChangedEventHandler(this.CanvasSizeChanged);
                if (!_contexts.TryGetValue(this._canvas, out this._context))
                {
                    _contexts[this._canvas] = this._context = new Context();
                }
                this._context.WindowOrder.Add(this);
                this.CanvasSizeChanged(this._canvas, null);
            }
        }

        private double CanvasHeight
        {
            get
            {
                if ((this.Canvas.ActualHeight == 0.0) && !double.IsNaN(this.Canvas.Height))
                {
                    return this.Canvas.Height;
                }
                return this.Canvas.ActualHeight;
            }
        }

        private double CanvasWidth
        {
            get
            {
                if ((this.Canvas.ActualWidth == 0.0) && !double.IsNaN(this.Canvas.Width))
                {
                    return this.Canvas.Width;
                }
                return this.Canvas.ActualWidth;
            }
        }

        public MessageBoxResult DialogResult
        {
            get { return (MessageBoxResult)GetValue(DialogResultProperty); }
            set { SetValue(DialogResultProperty, value); }
        }

        public bool IsActive
        {
            get { return (bool)GetValue(IsActiveProperty); }
            set { SetValue(IsActiveProperty, value); }
        }

        public bool IsDraggable
        {
            get { return (bool)GetValue(IsDraggableProperty); }
            set { SetValue(IsDraggableProperty, value); }
        }

        internal bool IsDragging
        {
            get { return (bool)GetValue(IsDraggingProperty); }
            set { SetValue(IsDraggingProperty, value); }
        }

        public bool IsResizable
        {
            get { return (bool)GetValue(IsResizableProperty); }
            set { SetValue(IsResizableProperty, value); }
        }

        public double Left
        {
            get { return (double)GetValue(LeftProperty); }
            set { SetValue(LeftProperty, value); }
        }

        public Brush ModalBackground
        {
            get { return (Brush)GetValue(ModalBackgroundProperty); }
            set { SetValue(ModalBackgroundProperty, value); }
        }

        public Brush MouseOverBrush
        {
            get { return (Brush)GetValue(MouseOverBrushProperty); }
            set { SetValue(MouseOverBrushProperty, value); }
        }

        public Brush PressedBrush
        {
            get { return (Brush)GetValue(PressedBrushProperty); }
            set { SetValue(PressedBrushProperty, value); }
        }

        public bool ShowCloseButton
        {
            get { return (bool)GetValue(ShowCloseButtonProperty); }
            set { SetValue(ShowCloseButtonProperty, value); }
        }

        public bool ShowMaximizeButton
        {
            get { return (bool)GetValue(ShowMaximizeButtonProperty); }
            set { SetValue(ShowMaximizeButtonProperty, value); }
        }

        public bool ShowMinimizeButton
        {
            get { return (bool)GetValue(ShowMinimizeButtonProperty); }
            set { SetValue(ShowMinimizeButtonProperty, value); }
        }

        public static ResourceDictionary ThemeResources
        {
            get
            {
                InitializeDefaultCanvas();
                return _defaultCanvas.Resources;
            }
            set
            {
                InitializeDefaultCanvas();
                _defaultCanvas.Resources = value;
            }
        }

        public double Top
        {
            get { return (double)GetValue(TopProperty); }
            set { SetValue(TopProperty, value); }
        }

        public WindowState WindowState
        {
            get { return (WindowState)GetValue(WindowStateProperty); }
            set { SetValue(WindowStateProperty, value); }
        }

        // Nested Types
        internal class Context
        {
            // Fields
            public GWindow ActiveWindow;
            public Rectangle ModalLayer = new Rectangle();
            public List<GWindow> ModalWindow = new List<GWindow>();
            public Popup Popup;
            public List<GWindow> PreviousActiveWindows = new List<GWindow>();
            public List<GWindow> WindowOrder = new List<GWindow>();
        }
    }
}
